/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package gui;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.math.Vector3f;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.mesh.IndexBuffer;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.util.BufferUtils;
import com.jme3.util.JmeFormatter;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.nio.FloatBuffer;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

/**
 *
 * @author jannes
 */
public class CanvasTreeGenerator{
    private static JmeCanvasContext context;
    private static Canvas canvas;
    private static AppTreeGenerator app;
    private static JFrame frame;       
    
    
    private static void createFrame(){        
        
        frame = new JFrame("Tree generator");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().setLayout(new BorderLayout());
        frame.addWindowListener(new WindowAdapter(){
            @Override
            public void windowClosed(WindowEvent e) {
                app.stop();
            }
        });                        
    }

    public static void createCanvas(){
        AppSettings settings = new AppSettings(true);
        settings.setWidth( Math.max(640, frame.getContentPane().getWidth()) );
        settings.setHeight( Math.max(480, frame.getContentPane().getHeight()) );
        
        app = new AppTreeGenerator();        
        
        app.setPauseOnLostFocus(false);
        app.setSettings(settings);
        app.createCanvas();

        context = (JmeCanvasContext) app.getContext();
        canvas = context.getCanvas();
        canvas.setSize(settings.getWidth(), settings.getHeight());
                
    }

    public static void startApp(){
        app.startCanvas();
        app.enqueue(new Callable<Void>(){
            public Void call(){
                if (app instanceof SimpleApplication){
                    SimpleApplication simpleApp = (SimpleApplication) app;
                    simpleApp.getFlyByCamera().setDragToRotate(true);
                }
                return null;
            }
        });        
        
    }

    public static void main(String[] args){
        JmeFormatter formatter = new JmeFormatter();

        Handler consoleHandler = new ConsoleHandler();
        consoleHandler.setFormatter(formatter);

        Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]);
        Logger.getLogger("").addHandler(consoleHandler);
        
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                JPopupMenu.setDefaultLightWeightPopupEnabled(false);
                createFrame();
                createCanvas();
                
                frame.getContentPane().add(canvas);
                frame.pack();
                startApp();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);  
                /*
                Mesh m = new Box(5, 4, 3);
                Box b = new Box(Vector3f.ZERO, 1, 2, 3); // create cube shape at the origin
                final Geometry geom = new Geometry("Box", b);  // create cube geometry from the shape
                while(app.getAssetManager() == null){
                    try {
                        Thread.sleep(1000l);
                    } catch (InterruptedException ex) {                        
                    }
                }
                Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");  // create a simple material
                mat.setColor("Color", ColorRGBA.Red);   // set color of material to blue
                geom.setMaterial(mat);                   // set the cube's material
                geom.updateModelBound();
                geom.move(-4, 0, 0);
                
                app.getRootNode().attachChild(geom);
                Spatial s = CrossSection.CreateCrossSection(50, geom, app.getRenderManager(), app.getAssetManager(), new File("assets/Textures/Test"), "test", 0);
                app.getRootNode().attachChild(s);
                
                app.getInputManager().addMapping("moveBox", new KeyTrigger(KeyInput.KEY_P));
                app.getInputManager().addListener(new ActionListener() {
                public void onAction(String name, boolean isPressed, float tpf) {
                    if(!isPressed){
                         if(geom.getWorldTranslation().x < 10){
                             geom.move(new Vector3f(1000,0,0));
                             System.out.println("a");
                         }else{
                             geom.move(new Vector3f(-1000,0,0));
                             System.out.println("b");
                         }
                    }
                }
                }, new String[]{"moveBox"});
                */
                loadTestTree();
            }
        });
    }
    
    private static void loadTestTree(){      
        while(app.getCamera() == null || app.getFlyByCamera() == null){
            try{
                Thread.sleep(100l);
            }catch(Exception exc){}
        }
        app.getCamera().setLocation(new Vector3f(0,8.0f,-20f));
        app.getCamera().lookAt(new Vector3f(0,8.0f,0), Vector3f.UNIT_Y);        
        app.getFlyByCamera().setMoveSpeed(5f);
        while(app.getAssetManager() == null){
            try{
                Thread.sleep(100l);
            }catch(Exception exc){}
        }                  
        final Node tree = (Node)app.getAssetManager().loadModel("Models/Trees/AspenAutumn/13_13_13_0.j3o");         
        //RenderCrossSectionTexture rcst = new RenderCrossSectionTexture(25, app.getRenderManager(), tree, (BoundingBox)tree.getWorldBound());         
        
        try{
            final int numberOfTreesInLine = 1;
            final int numberOfLines = 1;
            float distanceBetweenTrees = 10f;                                    
            final Node[] trees = new Node[numberOfTreesInLine*numberOfLines];            
            for(int i = 0; i < numberOfTreesInLine*numberOfLines; i++){
                trees[i] = tree.clone(true);                
                //trees[i].getChild("CrossSection").addControl(new CrossSectionControl());
                //trees[i].getChild("CrossSection").setQueueBucket(Bucket.Transparent);                                
                app.getRootNode().attachChild(trees[i]);
                printObjectCount(trees[i],0);
            }                        
            

            
            float xOffset = distanceBetweenTrees*(numberOfTreesInLine/2);
            for(int line = 0; line < numberOfLines; line++){
                for(int i = 0; i < numberOfTreesInLine; i++){
                    trees[line*numberOfTreesInLine+i].move(distanceBetweenTrees*i-xOffset, 0f , line*distanceBetweenTrees);
                }
            }                                   

            //((Geometry)tree.getChild("leaves")).getMesh().setPointSize(5.0f);
            //
                        
            //((Geometry)tree.getChild("leaves")).getMesh().setStatic();
            //app.getRootNode().attachChild(tree);                                                            
            
            app.getInputManager().addMapping("setLod0", new KeyTrigger(KeyInput.KEY_P));
            app.getInputManager().addListener(new ActionListener() {
                public void onAction(String name, boolean isPressed, float tpf) {
                    if(!isPressed){
                        for(int i = 0; i < numberOfTreesInLine*numberOfLines; i++){                         
                            trees[i].setLodLevel(0);                                                            
                        }             
                    }
                }
            }, new String[]{"setLod0"});
            
            app.getInputManager().addMapping("setLod1", new KeyTrigger(KeyInput.KEY_M));
            app.getInputManager().addListener(new ActionListener() {
                public void onAction(String name, boolean isPressed, float tpf) {
                    if(!isPressed){
                        for(int i = 0; i < numberOfTreesInLine*numberOfLines; i++){                         
                            trees[i].setLodLevel(1);                                                            
                        } 
                    }
                }
            }, new String[]{"setLod1"});
            
            
            app.getInputManager().addMapping("setLod2", new KeyTrigger(KeyInput.KEY_O));
            app.getInputManager().addListener(new ActionListener() {
                public void onAction(String name, boolean isPressed, float tpf) {
                    if(!isPressed){
                        for(int i = 0; i < numberOfTreesInLine*numberOfLines; i++){                         
                            trees[i].setLodLevel(2);   
                        } 
                    }
                }
            }, new String[]{"setLod2"});
            
            app.getInputManager().addMapping("setalpha", new KeyTrigger(KeyInput.KEY_L));
            app.getInputManager().addListener(new ActionListener() {
                public void onAction(String name, boolean isPressed, float tpf) {
                    if(!isPressed){
                        if(app.getCamera().isParallelProjection()){
                            app.getCamera().setParallelProjection(false);
                        }else{
                            app.getCamera().setParallelProjection(true);                                                        
                        }
                            //app.getRenderer().setAlphaToCoverage(true);                
                        //System.out.print("alpha to coverage set");
                    }
                }
            }, new String[]{"setalpha"});
            
            }catch(Exception exc){
            exc.printStackTrace();
        }        
    }                   
    
    private static void printObjectCount(Spatial spatial, int level){
        for(int i = 0; i < level; i++){
            System.out.print("    ");
        }
        if (spatial instanceof Node){
            List<Spatial> children = ((Node)spatial).getChildren();
            System.out.println(children.size());
            for(int i = 0; i < children.size(); i++){
                printObjectCount(children.get(i), level+1);
            }
        }else{
            System.out.println(0);
        }
                
        
    }
    
    private static void computeNormals(Mesh mesh) {
      Vector3f vector1 = new Vector3f();
      Vector3f vector2 = new Vector3f();
      Vector3f vector3 = new Vector3f();
       
      FloatBuffer vb = mesh.getFloatBuffer(Type.Position);
      IndexBuffer ib = mesh.getIndexBuffer();
      int tCount = mesh.getTriangleCount();
      int vCount = mesh.getVertexCount();
       
      // Get the current object
      // Here we allocate all the memory we need to calculate the normals      
      Vector3f[] normals = new Vector3f[vCount];
       
      // Go through all of the faces of this object
      for (int i = 0; i < vCount; i++) {
         //BufferUtils.populateFromBuffer(vector1, vb, ib.get(i*3));
         //BufferUtils.populateFromBuffer(vector2, vb, ib.get(i*3+1));
         //BufferUtils.populateFromBuffer(vector3, vb, ib.get(i*3+2));
         //vector1.subtractLocal(vector3);
         normals[i] = Vector3f.UNIT_Y;
      }
            
      mesh.setBuffer(Type.Normal,3,BufferUtils.createFloatBuffer(normals));
   }
       
}
